/* Copyright (c) 2009 - 2010 98Labs Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.sbal89.map.server;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.expressme.openid.Association;
import org.expressme.openid.Authentication;
import org.expressme.openid.Endpoint;
import org.expressme.openid.OpenIdException;
import org.expressme.openid.OpenIdManager;

@SuppressWarnings("serial")
public class OpenidServlet extends HttpServlet {
    static final long ONE_HOUR = 3600000L;
    static final long TWO_HOUR = ONE_HOUR * 2L;
    static final String ATTR_MAC = "openid_mac";
    static final String EXT_NS_ALIAS ="ensa";

    OpenIdManager manager;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        manager = new OpenIdManager();
        manager.setReturnTo("http://maps.electionexchange.ph/openid");
        manager.setRealm("http://maps.electionexchange.ph/");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String op = request.getParameter("op");
        if (op==null) {
        	try {
	            // check nonce:
	            checkNonce(request.getParameter("openid.response_nonce"));
	            // get authentication:
	            HttpSession session = request.getSession();
	            byte[] mac_key = (byte[]) session.getAttribute(ATTR_MAC);
	            String alias = (String) session.getAttribute(EXT_NS_ALIAS);
	            Authentication authentication = manager.getAuthentication(request, mac_key, alias);
	            // TODO: create user if not exist in database:
	            session.setAttribute("auth", authentication);
        	} catch (OpenIdException oie) {
        	}
    		request.getRequestDispatcher("WEB-INF/jsp/redirect.jsp").include(
    				request, response);
        }
        else {//if ("Google".equals(op) || "Yahoo".equals(op)) {
            // redirect to Google/Yahoo sign on page:
        	String alias = manager.lookupExtNsAlias(op);
            Endpoint endpoint = manager.lookupEndpoint(op);
            Association association = manager.lookupAssociation(endpoint);
            HttpSession session = request.getSession();
            
            session.setAttribute(ATTR_MAC, association.getRawMacKey());
            session.setAttribute(EXT_NS_ALIAS, alias);
            
            String url = manager.getAuthenticationUrl(endpoint, association);
            response.sendRedirect(url);
        }
//        else {
//            throw new ServletException("Bad parameter op=" + op);
//        }
    }

    void checkNonce(String nonce) {
        // check response_nonce to prevent replay-attack:
        if (nonce==null || nonce.length()<20)
            throw new OpenIdException("Verify failed.");
        long nonceTime = getNonceTime(nonce);
        long diff = System.currentTimeMillis() - nonceTime;
        if (diff < 0)
            diff = (-diff);
        if (diff > ONE_HOUR)
            throw new OpenIdException("Bad nonce time.");
        if (isNonceExist(nonce))
            throw new OpenIdException("Verify nonce failed.");
        storeNonce(nonce, nonceTime + TWO_HOUR);
    }

    boolean isNonceExist(String nonce) {
        // TODO: check if nonce is exist in database:
        return false;
    }

    void storeNonce(String nonce, long expires) {
        // TODO: store nonce in database:
    }

    long getNonceTime(String nonce) {
        try {
            return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
                    .parse(nonce.substring(0, 19) + "+0000")
                    .getTime();
        }
        catch(ParseException e) {
            throw new OpenIdException("Bad nonce time.");
        }
    }
}
